﻿//-----------------------------------------------------------------------
// <copyright file="Command.cs" company="Microsoft Corporation">
//  Copyright Microsoft Corporation. All Rights Reserved. This code released under the terms of the Microsoft Public License (MS-PL, http://opensource.org/licenses/ms-pl.html.) This is sample code only, do not use in production environments.    
// </copyright>
//-----------------------------------------------------------------------
namespace Microsoft.ALMRangers.VsarTreasureMap.WindowsStoreApp.MVVMSupport
{
    using System;
    using System.Threading;
    using System.Windows.Input;

    /// <summary>
    /// Provides an implementation of the <see cref="I:System.Windows.Input.ICommand"/> interface to enable commanding within applications.
    /// </summary>
    public class Command : ICommand
    {
        /// <summary>
        /// A predicate to determine whether the command can execute.
        /// </summary>
        private readonly Predicate<object> canExecute;

        /// <summary>
        /// An action to execute.
        /// </summary>
        private readonly Action execute;

        /// <summary>
        /// The event handler for the <see cref="E:Command.CanExecuteChanged"/> event.
        /// </summary>
        private EventHandler canExecuteChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="Command" /> class.
        /// </summary>
        /// <param name="execute">An action to execute.</param>
        public Command(Action execute)
            : this(execute, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Command"/> class.
        /// </summary>
        /// <param name="execute">An action to execute.</param>
        /// <param name="canExecute">A predicate to determine whether the command can execute.</param>
        public Command(Action execute, Predicate<object> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        /// <summary>
        /// Occurs when changes occur that affect whether or not the command should execute. 
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                this.canExecuteChanged += value;
            }

            remove
            {
                this.canExecuteChanged -= value;
            }
        }

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <c>null</c>.</param>
        /// <returns><c>true</c> if this command can be executed; otherwise, <c>false</c>.</returns>
        public bool CanExecute(object parameter)
        {
            if (this.canExecute == null)
            {
                return true;
            }

            return this.canExecute(parameter);
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <c>null</c>.</param>
        public void Execute(object parameter)
        {
            this.execute();
        }

        /// <summary>
        /// Raises the <see cref="E:Command.CanExecuteChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="T:EventArgs"/> instance containing the event data.</param>
        protected virtual void OnCanExecuteChanged(EventArgs e)
        {
            EventHandler handler = Interlocked.CompareExchange(ref this.canExecuteChanged, null, null);

            if (handler != null)
            {
                handler(this, e);
            }
        }
    }
}
